#ifndef IMAGE_TEXTURECUH
#define IMAGE_TEXTURECUH
#include"texture.cuh"

#include<texture_types.h>
#define STB_IMAGE_IMPLEMENTATION
#include"stb_image.h"
void creat_texture(const char*filename,
cudaTextureObject_t *ptr_texture,
cudaArray *d_cuArr);
void del_texture(cudaTextureObject_t *ptr_texture,cudaArray *d_cuArr);
class image_texture : public texture {
    public:
        __duel__ image_texture(cudaTextureObject_t texid) 
        {

            this->texid=texid;
        }
        __duel__ image_texture(){};
            

        __duel__ ~image_texture() 
        {
            
        }

        __device__ virtual vec3 value(double u, double v, const vec3& p) const 
        {
            float fr=tex2DLayered<float>(texid, u, 1-v, 0) ;
            float fg=tex2DLayered<float>(texid, u, 1-v, 1) ;
            float fb=tex2DLayered<float>(texid, u, 1-v, 2) ;
            
            return vec3(fr,fg,fb);
            

            
        }

    public:
        cudaTextureObject_t texid;
        
};

class host_Manager
{
public:
    host_Manager()
    {
        load_texture("E:/workplace/c++/cudatemp/earth.jpg");
    }
    ~host_Manager()
    {
        free_texture();
    }
    void load_texture(const char*filename)
    {
        creat_texture(filename,&tex_id,d_cuArr);
    }
    void free_texture()
    {
        del_texture(&tex_id,d_cuArr);
    }
    cudaTextureObject_t get_texId()
    {
        return tex_id;
    }
public:
    cudaArray *d_cuArr;
    cudaTextureObject_t tex_id;
};
void creat_texture(const char*filename,
cudaTextureObject_t *ptr_texture,
cudaArray *d_cuArr)
{
    
    int width, height, depth;
    const auto tex_data = stbi_load(filename,&width, &height, &depth, 0);
    if(!tex_data)
    {
        printf("errer load\n");
        exit(1);
    }
    
    const auto size = width * height * depth;
    float* h_data = new float[size];
    printf("LoadTexture %d,%d,%d\n", width, height, depth);
    for (unsigned int layer = 0; layer < depth; layer++)
    {
        for (auto i = 0; i < static_cast<int>(width * height); i++)
        {
            h_data[layer*width*height + i] = tex_data[i * depth + layer] / 255.0;
        }
            
    }
    printf("copy Texture Done!\n");
    cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc(32, 0, 0, 0, cudaChannelFormatKindFloat);
    //cuda Array
    
    checkCudaErrors(cudaMalloc3DArray(&d_cuArr, &channelDesc, make_cudaExtent(width, height, depth), cudaArrayLayered));


    cudaMemcpy3DParms myparms = { 0 };
    myparms.srcPos = make_cudaPos(0, 0, 0);
    myparms.dstPos = make_cudaPos(0, 0, 0);
    myparms.srcPtr = make_cudaPitchedPtr(h_data, width * sizeof(float), width, height);
    myparms.dstArray = d_cuArr;
    myparms.extent = make_cudaExtent(width, height, depth);
    myparms.kind = cudaMemcpyHostToDevice;
    cudaMemcpy3D(&myparms);
    printf("cudaMemcpy3DParms Texture Done!\n");

    cudaResourceDesc    texRes;
    memset(&texRes, 0, sizeof(cudaResourceDesc));
    texRes.resType = cudaResourceTypeArray;
    texRes.res.array.array = d_cuArr;
    printf("cudaResourceDesc Texture Done!\n");
    cudaTextureDesc     texDescr;
    memset(&texDescr, 0, sizeof(cudaTextureDesc));
    texDescr.filterMode = cudaFilterModeLinear;
    texDescr.addressMode[0] = cudaAddressModeWrap;   // clamp
    texDescr.addressMode[1] = cudaAddressModeWrap;
    texDescr.addressMode[2] = cudaAddressModeWrap;
    texDescr.readMode = cudaReadModeElementType;
    texDescr.normalizedCoords = true;
    printf("cudaTextureDesc Texture Done!\n");
    checkCudaErrors(cudaCreateTextureObject(ptr_texture, &texRes, &texDescr, NULL));
    printf("cudaCreateTextureObject Texture Done!\n");
    delete h_data;
    stbi_image_free(tex_data);
    h_data=nullptr;
    printf("Load Texture Done!\n");
}
void del_texture(cudaTextureObject_t *ptr_texture,cudaArray *d_cuArr)
{
    cudaDestroyTextureObject(*ptr_texture);
    cudaFreeArray(d_cuArr);
}



#endif